// Debug City Renderer

import I = require("./Interfaces");

// city reference
import City = require("../MiddleLayer/Execution/City");

// import robot karel
import Robot = require("../MiddleLayer/Execution/RobotKarel");

// import image library
import Img = require("./ImageLibrary");

// import execution engine
import Exec = require("../MiddleLayer/Execution/ExecutionEngine");



// Debugging City Renderer
export class DebugCityRenderer implements I.ICityRenderer {

    // canvas and 2D renderer properties
    private mCanvas: HTMLCanvasElement;
    private mCtx: CanvasRenderingContext2D;

    private mCity: City.City;
    private mKarel: Robot.RobotKarel;
    private mEngine: Exec.ExecutionEngine;

    // image library
    private mImageLibrary: Img.ImageLibrary;

    // constructor
    public constructor(canvasId: string) {
        // get canvas
        this.mCanvas = <HTMLCanvasElement>document.getElementById(canvasId);
        if (this.mCanvas == undefined || this.mCanvas == null)
            throw "Wrong canvas ID";

        // get the 2D context
        this.mCtx = this.mCanvas.getContext("2d");
        if (this.mCtx == null || this.mCtx == undefined)
            throw "Cannot get renedering context.";

        // reference city and robot Karel classes
        this.mCity = City.City.Instance;
        this.mKarel = Robot.RobotKarel.Instance;
        this.mImageLibrary = Img.ImageLibrary.Instance;
        this.mEngine = Exec.ExecutionEngine.Instance;
    }

    public GetFieldByMouse(mouseX: number, mouseY: number): Array<number> {
        // returns the field
        var field = new Array<number>(2);

        // get the field size
        var fieldSize = this.CalculateFieldSize();

        // convert to the coordinates
        var col = Math.floor(mouseX / fieldSize);
        var row = Math.floor(mouseY / fieldSize);
        row = this.mCity.RealSize - 1 - row;

        // check if outside bounds
        if (row < 1 || col < 1 || row > this.mCity.InternalSize || col > this.mCity.InternalSize)
            return null;

        // return the result
        field[0] = row;
        field[1] = col;
        return field;       
    }



    // The main render method
    public Render(): void {
        // get the field size
        var fieldSize = this.CalculateFieldSize();
    
        // clears the background
        this.ClearBackground();

        // draws the basic grid
        this.DrawGrid(fieldSize);

        // render the content of the city
        this.RenderContent(fieldSize);

        // check the pause message to render
        if (this.mEngine.IsPaused) {
            this.RenderPauseMessage();
        }
    }

    // renders the pause message
    private RenderPauseMessage() {
        // constant variables
        var fontFactor = 0.2;
        var message = "Pauza";

        // font measuring
        var width = this.mCanvas.width;
        var height = this.mCanvas.height;
        var fontSize = Math.round(height * fontFactor);

        // setting font properties
        this.mCtx.fillStyle = "rgba(255,128,128,0.7)";
        this.mCtx.strokeStyle = "rgb(255,255,255)";
        this.mCtx.font = fontSize.toString() + "px Arial Bold";
        this.mCtx.textAlign = "center";
        this.mCtx.textBaseline = "middle";

        // render the text
        this.mCtx.fillText(message, width / 2, height / 2);
        this.mCtx.strokeText(message, width / 2, height / 2);
    }

    // the main method rendering the content of the Karel's city
    private RenderContent(fieldSize: number): void {
        for (var row = 0; row < this.mCity.RealSize; row++) {
            var cityRow = this.mCity.RealSize - 1 - row;
            for (var col = 0; col < this.mCity.RealSize; col++) {
                var x = col * fieldSize;
                var y = row * fieldSize;

                // if is wall
                if (this.mCity.IsWall(cityRow, col)) {
                    this.DrawWall(x, y, fieldSize);
                }
                else {
                    // if position of robot Karel
                    if (this.mKarel.Row == cityRow && this.mKarel.Col == col) {
                        this.DrawKarel(x, y, fieldSize);
                    } else {
                        var markCount = this.mCity.GetNumberOfMarks(cityRow, col);
                        if (markCount > 0) {
                            this.DrawMarks(x, y, fieldSize, markCount);
                        }
                    }
                }
            }
        }
    }

    // draws the marks on the field
    private DrawMarks(x: number, y: number, size: number, markCount: number): void {
        // init vars
        var margin = 1;
        var maxMarks = 8;
        markCount = Math.min(maxMarks, markCount);

        // calculate marks
        var height = (size - 2 * margin) / maxMarks;
        var width = size - 2 * margin;

        x += margin;
        y += (maxMarks - 1) * height;

        // draw marks
        this.mCtx.fillStyle = "violet";

        while (markCount--) {
            this.mCtx.fillRect(x, y + margin, width, height - 2 * margin);
            y -= height;
        }
    }

    // draw Karel
    private DrawKarel(x: number, y: number, size: number): void {
        var image: HTMLImageElement;
        // choose image
        switch (this.mKarel.Direction) {
            case Robot.eKarelDirection.North:
                image = this.mImageLibrary.GetImage(Img.eImageID.KarelNorth);
                break;
            case Robot.eKarelDirection.South:
                image = this.mImageLibrary.GetImage(Img.eImageID.KarelSouth);
                break;
            case Robot.eKarelDirection.East:
                image = this.mImageLibrary.GetImage(Img.eImageID.KarelEast);
                break;
            case Robot.eKarelDirection.West:
                image = this.mImageLibrary.GetImage(Img.eImageID.KarelWest);
                break;
        }

        this.mCtx.drawImage(image, 0, 0, image.width, image.height, x, y, size, size);
    }

    // renders the wall
    private DrawWall(x: number, y: number, size: number): void {
        var wallImage = this.mImageLibrary.GetImage(Img.eImageID.Brick);
        this.mCtx.drawImage(wallImage, 0, 0, wallImage.width, wallImage.height, Math.floor(x), Math.floor(y), Math.ceil(size), Math.ceil(size));
    }

    // clears background
    private ClearBackground() {
        var size = this.mCanvas.clientWidth;
        this.mCtx.fillStyle = "rgb(0,0,0)";
        this.mCtx.fillRect(0, 0, size, size);
    }

    // draws the basic grid
    private DrawGrid(fieldSize: number): void {
        for (var row = 0; row < this.mCity.RealSize; row++) {
            var cityRow = this.mCity.RealSize - 1 - row;
            for (var col = 0; col < this.mCity.RealSize; col++) {

                // in some browsers looks ugly if not checked
                if (this.mCity.IsWall(cityRow, col) == false) {
                    var x = col * fieldSize;
                    var y = row * fieldSize;

                    this.mCtx.strokeStyle = "yellow";
                    this.mCtx.strokeRect(x, y, fieldSize, fieldSize);
                }
            }
        }
    }

    // returns the field size
    private CalculateFieldSize(): number {
        var size = this.mCanvas.clientWidth;
        return size / this.mCity.RealSize;
    }
}
